/* 
 * Copyright (c) 2010 Adam Markiewicz
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 * @file meta/lang.h
 * @author Adam Markiewicz
 */

#ifndef __CLEA_META_LANG
#define __CLEA_META_LANG

/**
 * @defgroup meta Meta-programming
 * 
 * This module contains structures useful in template meta-programming. It 
 * provides basic logical operations and type comparison. Framework is based on 
 * structs, where operation result can be accessed through member enum "value".
 * 
 * @code
 * #include <meta/lang.h>
 * 
 * using namespace Clea::Meta;
 * 
 * ...
 * 
 * EqualType<int, int>::value;    // true
 * EqualType<int, bool>::value;   // false
 * 
 * And<EqualType<char, char>::value, NotEqualType<int, bool>::value>::value; // true
 * @endcode
 */

namespace Clea
{
    namespace Meta
    {
        /**
         * @brief Logical equality
         * 
         * @ingroup meta
         * 
         * @tparam e1 Expression 1
         * @tparam e2 Expression 2
         */
        template <bool e1, bool e2>
        struct Equal
        {
            enum { value = 0 };
        };
        
        template <>
        struct Equal<true, true>
        {
            enum { value = 1 };
        };
        
        template <>
        struct Equal<false, false>
        {
            enum { value = 1 };
        };
        
        /**
         * @brief Logical inequality
         * 
         * @ingroup meta
         * 
         * 
         * @tparam e1 Expression 1
         * @tparam e2 Expression 2
         */
        template <bool e1, bool e2>
        struct NotEqual
        {
            enum { value = 1 };
        };
        
        template <>
        struct NotEqual<true, true>
        {
            enum { value = 0 };
        };
        
        template <>
        struct NotEqual<false, false>
        {
            enum { value = 0 };
        };
        
        /**
         * @brief Logical negation
         * 
         * @ingroup meta
         * 
         * @tparam e Expression
         */
        template <bool e>
        struct Not
        {
            enum { value = 0 };
        };
        
        template <>
        struct Not<false>
        {
            enum { value = 1 };
        };
        
        /**
         * @brief Logical and
         * 
         * @ingroup meta
         * 
         * @tparam e1 Expression 1
         * @tparam e2 Expression 2
         */
        template <bool e1, bool e2>
        struct And
        {
            enum { value = 0 };
        };
        
        template <>
        struct And<true, true>
        {
            enum { value = 1 };
        };
        
        /**
         * @brief Logical nand
         * 
         * @ingroup meta
         * 
         * @tparam e1 Expression 1
         * @tparam e2 Expression 2
         */
        template <bool e1, bool e2>
        struct Nand
        {
            enum { value = 1 };
        };
        
        template <>
        struct Nand<true, true>
        {
            enum { value = 0 };
        };
        
        /**
         * @brief Logical or
         * 
         * @ingroup meta
         * 
         * @tparam e1 Expression 1
         * @tparam e2 Expression 2
         */
        template <bool e1, bool e2>
        struct Or
        {
            enum { value = 1 };
        };
        
        template <>
        struct Or<false, false>
        {
            enum { value = 0 };
        };
        
        /**
         * @brief Logical nor
         * 
         * @ingroup meta
         * 
         * @tparam e1 Expression 1
         * @tparam e2 Expression 2
         */
        template <bool e1, bool e2>
        struct Nor
        {
            enum { value = 0 };
        };
        
        template <>
        struct Nor<false, false>
        {
            enum { value = 1 };
        };
        
        /**
         * @brief Logical xor
         * 
         * @ingroup meta
         * 
         * @tparam e1 Expression 1
         * @tparam e2 Expression 2
         */
        template <bool e1, bool e2>
        struct Xor
        {
            enum { value = 0 };
        };
        
        template <>
        struct Xor<true, false>
        {
            enum { value = 1 };
        };
        
        template <>
        struct Xor<false, true>
        {
            enum { value = 1 };
        };
        
        /**
         * @brief Types equality
         * 
         * @ingroup meta
         * 
         * @tparam T1 Type 1
         * @tparam T2 Type 2
         */
        template <typename T1, typename T2>
        struct EqualType
        {
            enum { value = 0 };
        };
        
        template <typename T>
        struct EqualType<T, T>
        {
            enum { value = 1 };
        };
        
        /**
         * @brief Types inequality
         * 
         * @ingroup meta
         * 
         * @tparam T1 Type 1
         * @tparam T2 Type 2
         */
        template <typename T1, typename T2>
        struct NotEqualType
        {
            enum { value = 1 };
        };
        
        template <typename T>
        struct NotEqualType<T, T>
        {
            enum { value = 0 };
        };
    }
}

#endif // __CLEA_META_LANG
